New action Pulse

The Hasselt code has defined several actions for its outputs: On, Off, Toggle and PWM. My house’s lighting system uses pulse relays so I couldn’t really use any of these actions, I need the action to put a short pulse on the output. So I wrote a new action called Pulse.

Firmware

The DoDM() function will get a new action:

case ACTION_PULSE: 		// Disable relays
	doActionPulse(dmflags,  readEEPROM( VSCP_EEPROM_END + REG_DESCISION_MATRIX + ( 8 * i ) + 			VSCP_DM_POS_ACTIONPARAM  ) );
	break;

The function doActionPulse() will perform some tests to see if the event should be treated (e.g. if the zone and subzone match flags are set and if so if they match). It will then call PulseOut(). That’s were the actual pulse is set.

In order to put a pulse on an output pin, the Pulse action first needs to pull the pin low, then set it high, wait for a while, and then pull it low again. The crux is in the waiting; if we do this with a simple delay function, all our code will be blocked during the wait. To avoid thus, we’ll be handling the delay using an interrupt.

The PulseOut() function uses a struct PulseOutOutputVar, which holds two variables; Active signals that the output is currently pulsing, and Counter is set to the value of general purpose counter counter_10ms, and is used to track when the pulse should end. PulseOutputVar is an array of 8 elements, one for each output.

struct PulseOutputStruct {
	BOOL Active;                     // Channel is being pulsed
	unsigned short Counter;          // Pulse duration counter for PulseOut()
} PulseOutputVar[8];

In the PulseOut() function we have the following code:

SetOut(output, OUTPUT_OFF);                        // set output low, as starting point for pulse
PulseOutputVar[output-1].Active = TRUE;            // PulseOutputVar's range is 0-7
PulseOutputVar[output-1].Counter = counter_10ms;   // set this output's counter, main() WHILE-loop watches this to set falling edge of pulse
SetOut(output, OUTPUT_ON);                         // set output high, i.e. rising edge of pulse

So after this bit of code we have constructed the rising edge of our pulse, and have set a counter. This counter will be used in the while(1)-loop in main() to check when to set the output low again.

// *** Handle PulseOut() logic
for (i=0; i<8; i++) {           // for each output
    if (PulseOutputVar[i].Active) { // if channel is being pulsed
        if ( counter_10ms >= ( PulseOutputVar[i].Counter + PULSE_OUT_PERIOD )%256 ) {     // if at least 10 * 10ms has elapsed, % operator make counter cyclic
            SetOut(i+1, OUTPUT_OFF);        // Switch output off = falling edge of pulse  //xxx
            PulseOutputVar[i].Active = FALSE;   // done pulsing, reset pulse status for output
        }
    }
}

This loop checks, for each output, if the output is currently in the process of generating a pulse, and if so, if it is time to end the pulse. If so, it stops the pulse and sets the pulse active variable to FALSE.

The output pin will be set low once the current general purpose counter counter_10ms reaches PULSE_OUT_PERIOD ticks after we set PulseOutputVar[i].Counter. Given the 10ms period followed by counter_10ms, setting PULSE_OUT_PERIOD to 10 means the pin will be pulled low after 100ms. We can change the pulse duration by changing the value of the PULSE_OUT_PERIOD label which is defined in VSCP_node_defines.h.

To support this code, a new general counter variable counter_10ms is introduced. This is a simple counter which is incremented in the interrupt routine isr_low.

counter_10ms++;

The while(1)-loop exectutes every 380us. To check this I’ve toggled a spare output pin, and measured the pulse period with the oscilloscope.

while ( 1 ) {           // Loop Forever
#ifdef DEBUG_DEBUGPIN
    DEBUG_PIN = ~DEBUG_PIN; // toggle debugpin
#endif

MDF

A new action needs to be added to the MDF:

<action code="0x03">				
	<name lang="en">Pulse output(s)</name>
		<description lang="en">
			Pulse output(s) given by argument. The argument is a bit array where bit 0 is output 1 and so on.\n
			Byte 1 is Zone and byte 2 is zone page and must be equal to register content to trigger action.	
		</description>
   	<param>							
		<name lang="en">Bitarry for output</name>
		<description lang="en">
			A bitarray where the first bit represents output one and so on.
		</description>
 	   
		<bit pos="0" default="false">
			<name lang="en">output 1</name>
			<description lang="en">Set to one to select output 1</description>
		</bit>
		<bit pos="1" default="false">
			<name lang="en">output 1</name>
			<description lang="en">Set to one to select output 1</description>
		</bit>  
		<bit pos="2" default="false">
			<name lang="en">output 2</name>
			<description lang="en">Set to one to select output 2</description>
		</bit>  
		<bit pos="3" default="false">
			<name lang="en">output 3</name>
			<description lang="en">Set to one to select output 3</description>
		</bit>  
		<bit pos="4" default="false">
			<name lang="en">output 4</name>
			<description lang="en">Set to one to select output 4</description>
		</bit>  
		<bit pos="5" default="false">
			<name lang="en">output 5</name>
			<description lang="en">Set to one to select output 5</description>
		</bit>  
		<bit pos="6" default="false">
			<name lang="en">output 6</name>
			<description lang="en">Set to one to select output 6</description>
		</bit>  
		<bit pos="7" default="false">
			<name lang="en">output 7</name>
			<description lang="en">Set to one to select output 7</description>
		</bit>
	</param>
</action>	

The action code=”0x03” needs to correspond to the ACTION_PULSE label as defined in VSCP_node_defines.h.

Decision Matrix

The DM of the node needs to be configured to use the Pulse action.

Resources

Comments